#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include <unistd.h>
#include <sys/stat.h> // 用于 struct stat 结构体和 S_ISREG 宏
#include <fstream>
#include <vector>
#include <boost/algorithm/string.hpp>
// #include <functional>

namespace ns_util
{
    static const int SIZE = 1024;
    // 1、工具一：实现时间戳转化成[年-月-日 时:分:秒]
    class TimeUtil
    {
    public:
        /*************************
         * 功能：获取一个格式化的时间
         * 格式：[年-月-日 时:分:秒]
         ***************************/
        static std::string GetFormatTime()
        {
            time_t t = time(nullptr);
            struct tm *ctime = localtime(&t);
            char timestr[SIZE];
            snprintf(timestr, sizeof(timestr), "[%d-%d-%d %d:%d:%d]",
                     ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                     ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

            return timestr;
        }
        /*****************
         * 功能：获取一个毫秒级别的时间戳，转化为字符串
         */
        static std::string GetMsTime()
        {
            struct timespec ts;
            clock_gettime(CLOCK_REALTIME, &ts);

            std::string ctime = std::to_string(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
            return ctime;
        }
    };
    static const std::string defaultfilepath = "./temp/";
    class PathSpliceUtil // 用于对编译文件的路径拼接
    {
    private:
        /***************************
         * 功能：拼接一个 临时文件路径 + 文件名 + 后缀
         * 返回值："./temp/xxx.suffix"
         ****************************/
        static std::string Splice(const std::string &filename, const std::string &suffix)
        {
            return defaultfilepath + filename + suffix;
        }

    public:
        // 编译时期的后缀添加
        static std::string Exe(const std::string &filename)
        {
            return Splice(filename, ".exe");
        }
        static std::string Src(const std::string &filename)
        {
            return Splice(filename, ".cc");
        }
        static std::string Compilerr(const std::string &filename)
        {
            return Splice(filename, ".compilerr");
        }
        // 运行时期的结果后缀
        static std::string Stderr(const std::string &filename)
        {
            return Splice(filename, ".stderr");
        }
        static std::string Stdin(const std::string &filename)
        {
            return Splice(filename, ".stdin");
        }
        static std::string Stdout(const std::string &filename)
        {
            return Splice(filename, ".stdout");
        }
    };

    class FileUtil // 文件工具类
    {
    public:

        // /**********************
        //  * 获取到的行和文件内容处理进行分离
        //  ********************/
        // using linefunc = std::function<bool(std::string &conten)>;
        // static bool DealFileOneLine(const std::string &file, linefunc func)
        // {
        //     std::ifstream ifs(file);
        //     if (!ifs.is_open())
        //     {
        //         return false;
        //     }
        //     std::string oneline;
        //     while (std::getline(ifs, oneline))
        //     {
        //         func(oneline);
        //     }
        //     ifs.close();
        // }

        /*******
         * 功能：判断一个带路径的文件是否存在
         *******/
        static bool IsFileExists(const std::string &file) // 传入带路径的文件
        {
            // //判断一个文件是否存在
            // struct stat st;
            // std::cout << file << std::endl;
            // //if(::access(file.c_str(), F_OK) == 0)
            // if(stat(file.c_str(), &st) == 0)
            // {
            //     return true;
            // }
            // return false;

            struct stat st;
            // 1. 先判断路径是否存在
            if (stat(file.c_str(), &st) != 0)
            {
                return false; // 路径不存在
            }
            // 2. 再判断是否为普通文件（排除目录、设备文件等）
            if (!S_ISREG(st.st_mode))
            {
                // std::cout << "路径存在但不是文件: " << file << std::endl; // 调试用
                return false;
            }
            return true;
        }

        /******
         * 功能：实现得到一个具有唯一的文件名(没有路径、没有后缀)
         * 方案：毫秒级别时间戳 + '_' + 动态增长的整型
         */
        static std::string UniqFileName()
        {
            static int num = 0; // 随使用次数而增加
            ++num;

            std::string filename = TimeUtil::GetMsTime() + "_" + std::to_string(num); // 获取唯一的文件名

            return filename;
        }
        /***************************
         * 函数功能：创建一个源文件，并将内容写入
         * 参数说明：
         * file: 带具体路径的文件
         * content: 需要写入的内容
         * 返回值: 表明是否写入成功
         ****************************/
        static bool WriteFile(const std::string &file, const std::string &content)
        {
            std::ofstream ofs(file, std::ios::binary); // 处理换行
            if (!ofs.is_open())
            {
                // 没有打开
                return false;
            }
            // 文件成功打开
            ofs.write(content.c_str(), content.size());
            //
            return true;
        }

        /***************************
         * 函数功能：读取一个文件的内容
         * 参数说明：
         * file: 带具体路径的文件
         * content: 需要带出的内容
         * 返回值: 表明是否读取成功
         ****************************/
        static bool ReadFile(const std::string &file, std::string *content)
        {
            // 1. 清空输出内容（防止残留旧数据）
            content->clear();

            // 2. 以二进制模式打开文件（跨平台兼容，避免换行符转换）
            std::ifstream ifs(file, std::ios::binary);
            if (!ifs.is_open())
            {
                return false; // 文件不存在或权限不足
            }

            // 3. 定义临时缓冲区（固定大小，无需动态分配）
            static const size_t BUFFER_SIZE = 40 * 1024; // 4KB缓冲区（可根据需求调整）
            char buffer[BUFFER_SIZE];                    // 栈上分配的临时缓冲区，无堆内存操作

            // 4. 逐块读取文件，追加到content
            while (ifs.read(buffer, BUFFER_SIZE))
            {
                // 读取到完整缓冲区：追加全部内容
                content->append(buffer, BUFFER_SIZE);
            }

            // 5. 处理最后一块不完整的数据（若文件大小不是BUFFER_SIZE的整数倍）
            if (ifs.gcount() > 0)
            {
                content->append(buffer, ifs.gcount());
            }

            // 6. 检查读取过程是否出错（排除EOF正常结束的情况）
            return !ifs.bad();
        }

        /*********************
         * 功能：删除一个文件
         * 参数：file
         ********************/
        static bool UnlinkFile(const std::string &file)
        {
            int n = -1;
            if (IsFileExists(file))   // 如果对应文件存在
                unlink(file.c_str()); // 删除该文件
            return n == 0;
        }
    };

    class StringUtil // 字符串类的工具
    {
    public:
        /********************
         * 功能：对传入的指定字符串，对特定的字符进行分割
         * 参数：
         *  1. str: 需要进行分割的字符串
         *  2. out: 带出的内容
         *  3. seq: 分割符
         *********************/
        static void SplitString(const std::string &str, std::vector<std::string> *out, const std::string &seq)
        {
            // 使用boost库
            boost::split((*out), str, boost::is_any_of(seq), boost::algorithm::token_compress_on);
        }
    };
}